package jt.classic.system.workflow;

import jt.classic.system.ISystem;
import jt.classic.system.SimpleManager;
import jt.classic.system.group.GroupJsonBean;
import jt.classic.system.group.GroupJsonBean4Chk;
import jt.classic.system.user.IUser;
import jt.classic.system.utils.AnnexTool;
import jt.classic.system.workflow.impl.WFlowImpl;
import jt.classic.system.workflow.impl.WHandleImpl;
import jt.classic.system.workflow.impl.WStepImpl;
import jt.classic.system.workflow.impl.WTrendImpl;

import org.dom4j.Document;
import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import org.limp.basework.SimpleBean;
import org.limp.basework.SimpleBean4Table;
import org.limp.basework.Table;
import org.limp.basework.analyzer.TableRegisterCenter;
import org.limp.basework.impl.SimpleBean4TableImpl;
import org.limp.basework.impl.SimpleBeanImpl;
import org.limp.basework.tools.BaseworkUtil;

import org.limp.mine.DataTrimmerI;
import org.limp.mine.DataTrimmerI.DataItemList;
import org.limp.mine.StringTool;
import org.limp.mine.XMLTool;
import org.limp.mine.annex.AnnexInfo;

import java.io.StringReader;

import java.sql.Connection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * 工作流程管理者类
 *
 * @author bizkit
 *
 */
public class WorkflowManager extends SimpleManager {
    public WorkflowManager(Connection conn) {
        super(conn);
    }

    public WorkflowManager() {
        super();
    }

    /**
     * 是否存在唯一标识
     * @param key 流程key
     * @return boolean
     */
    public boolean containsKey(String key) {
        String sql = "SELECT * FROM WF_CATEGORY WHERE CG_KEY = '" + key + "'";

        return this.trimmer.haveMoreData(sql);
    }

    /**
     * 删除流程定义
     *
     * @param gid 流程ID
     * @throws WorkflowException
     */
    public void deleteFlow(String gid) throws WorkflowException {
        StringBuffer sql = new StringBuffer();

        sql.append(
            "DELETE FROM WF_TREND WHERE S_ID IN (SELECT S_ID FROM WF_STEP WHERE CG_ID = " +
            gid + ");");
        sql.append(
            "DELETE FROM WF_TREND WHERE TREND_ID IN (SELECT S_ID FROM WF_STEP WHERE CG_ID = " +
            gid + ");");

        sql.append(
            "DELETE FROM WF_HANDLE WHERE S_ID IN (SELECT S_ID FROM WF_STEP WHERE CG_ID = " +
            gid + ");");

        sql.append("DELETE FROM WF_STEP WHERE CG_ID = " + gid + ";");
        sql.append("DELETE FROM WF_CATEGORY WHERE CG_ID = " + gid + ";");

        if (!this.trimmer.executeBatch(sql.toString())) {
            throw new WorkflowException("删除流程定义出现异常");
        }
    }

    /**
     * 根据流程类别ID得到流程类别实例
     * @param id 流程类别ID
     * @return WFlow
     */
    public WFlow getWFlowById(String id) {
        String sql = "SELECT * FROM WF_CATEGORY WHERE CG_ID = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(id);

        Map info = this.trimmerI.searchSingleData(sql, dil);
        WFlow flow = null;

        if (info != null) {
            flow = new WFlowImpl();

            String okey = (String) info.get("OBJ_NAME");
            WObjectRegister register = WObjectRegister.getInstance();
            WObject obj = null;

            try {
                obj = register.findWObject(okey);
                info.put("OBJECT", obj);
            } catch (Exception ex) {
                ISystem.catchException(this, ex);
            }

            List list = new ArrayList();
            list.add(obj);

            info.put("OBJECTS", list);

            sql = "SELECT * FROM WF_STEP WHERE CG_ID = ? ORDER BY S_NO ASC";

            List s = this.trimmerI.searchMultiData(sql, dil);

            info.put("MAXSTEPNO", String.valueOf(s.size()));

            sql = "SELECT * FROM WF_STEP WHERE CG_ID = ? AND S_STATUS = 0";

            List steps = this.trimmerI.searchMultiData(sql, dil);

            for (int i = 0; i < steps.size(); i++) {
                Map temp = (Map) steps.get(i);

                String sid = (String) temp.get("S_ID");

                String[] lastid = this.getStepLastID(sid);

                temp.put("S_LASTID", lastid);

                List trends = this.getStepTrend(sid);

                temp.put("TRENDS", trends);

                List handles = this.getStepHandle(sid);

                temp.put("HANDLES", handles);

                WStep step = new WStepImpl(flow);
                step.reload(temp);
                steps.set(i, step);
            }

            info.put("STEPS", steps);

            flow.reload(info);
        }

        return flow;
    }

    /**
     * 根据流程类别ID得到流程类别实例
     * @param key 流程类别key
     * @return WFlow
     */
    public WFlow getWFlowByKey(String key) {
        String sql = "SELECT * FROM WF_CATEGORY WHERE CG_KEY = '" + key + "'";
        Map info = this.trimmer.searchSingleData(sql);
        WFlow flow = null;

        if (info != null) {
            String id = (String) info.get("CG_ID");

            flow = new WFlowImpl();

            String okey = (String) info.get("OBJ_NAME");
            WObjectRegister register = WObjectRegister.getInstance();
            WObject obj = null;

            try {
                obj = register.findWObject(okey);
                info.put("OBJECT", obj);
            } catch (Exception ex) {
                ISystem.catchException(this, ex);
            }

            List list = new ArrayList();
            list.add(obj);

            info.put("OBJECTS", list);

            sql = "SELECT * FROM WF_STEP WHERE CG_ID = " + id +
                " ORDER BY S_NO ASC";

            List s = this.trimmer.searchMultiData(sql);

            info.put("MAXSTEPNO", String.valueOf(s.size()));

            sql = "SELECT * FROM WF_STEP WHERE CG_ID = " + id;

            List steps = this.trimmer.searchMultiData(sql);

            for (int i = 0; i < steps.size(); i++) {
                Map temp = (Map) steps.get(i);

                String sid = (String) temp.get("S_ID");

                String[] lastid = this.getStepLastID(sid);

                temp.put("S_LASTID", lastid);

                List trends = this.getStepTrend(sid);

                temp.put("TRENDS", trends);

                List handles = this.getStepHandle(sid);

                temp.put("HANDLES", handles);

                WStep step = new WStepImpl(flow);
                step.reload(temp);
                steps.set(i, step);
            }

            info.put("STEPS", steps);

            flow.reload(info);
        }

        return flow;
    }

    /**
     * 根据环节ID得到环节实例
     * @param id 环节ID
     * @return WStep
     */
    public WStep getStepByID(String id) {
        WStep step = null;

        String sql = "SELECT CG_ID FROM WF_STEP WHERE S_ID = " + id;

        Map info = this.trimmer.searchSingleData(sql);

        if (info != null) {
            String gid = (String) info.get("CG_ID");

            WFlow flow = this.getWFlowById(gid);

            step = flow.istep(id);
        }

        return step;
    }

    /**
     * 从流程设计器中同步流程脚本
     * @param id 流程ID
     * @param xml 流程xml脚本
     */
    public void synFromFlowDrawing(String id, String xml)
        throws WorkflowException {
        try {
            SAXReader reader = new SAXReader();

            reader.setEncoding(XMLTool.DEFAULT_ENCODING);

            Document document = reader.read(new StringReader(xml));

            Element activities = document.getRootElement().element("Activities");

            WFlow flow = this.getWFlowById(id);

            if (activities != null) {
                Map newStepMap = new HashMap();

                Iterator iter = activities.elementIterator("Activitie");

                if (iter != null) {
                    while (iter.hasNext()) {
                        Element activitie = (Element) iter.next();

                        String stepno = StringTool.checkString(activitie.attributeValue(
                                    "id"));
                        String steptype = StringTool.checkString(activitie.attributeValue(
                                    "type"));
                        String stepname = StringTool.checkString(activitie.attributeValue(
                                    "name"));

                        String xCoordinate = StringTool.checkString(activitie.attributeValue(
                                    "xCoordinate"));

                        String yCoordinate = StringTool.checkString(activitie.attributeValue(
                                    "yCoordinate"));

                        if (steptype.equals("START_NODE")) {
                            steptype = "0";
                        } else if (steptype.equals("END_NODE")) {
                            steptype = "-1";
                        } else {
                            steptype = "1";
                        }

                        BaseworkUtil util = new BaseworkUtil();

                        SimpleBean sb = new SimpleBeanImpl();

                        if (this.exitsStep(id, stepno)) {
                            Map stepInfo = this.getStepByNo(id, stepno);

                            String stepid = (String) stepInfo.get("S_ID");

                            newStepMap.put(stepno, stepid);

                            sb.getResource().put("xc", xCoordinate);
                            sb.getResource().put("yc", yCoordinate);
                            sb.getResource().put("iname", stepname);
                            sb.getResource().put("itype", steptype);
                            sb.getResource().put("sid", stepid);

                            util.manualUpdate("WF_STEP", sb, this.conn);

                            /*清理该环节的相关流向定义*/
                            String sql = "DELETE FROM WF_TREND WHERE S_ID = " +
                                stepid;

                            sql += (";DELETE FROM WF_TREND WHERE TREND_ID = " +
                            stepid);

                            this.trimmer.executeBatch(sql);
                        } else {
                            sb.getResource().put("xc", xCoordinate);
                            sb.getResource().put("yc", yCoordinate);
                            sb.getResource().put("ino", stepno);
                            sb.getResource().put("iname", stepname);
                            sb.getResource().put("itype", steptype);
                            sb.getResource().put("irangetype", "1");
                            sb.getResource().put("gid", id);

                            Map result = util.manualSave("WF_STEP", sb,
                                    this.conn);

                            String _stepId = (String) result.get("S_ID");

                            newStepMap.put(stepno, _stepId);
                        }
                    }
                }

                Element transitions = document.getRootElement().element("Transitions");

                if (transitions != null) {
                    Iterator iter1 = transitions.elementIterator("Transition");

                    if (iter1 != null) {
                        while (iter1.hasNext()) {
                            Element transition = (Element) iter1.next();

                            String tranName = StringTool.checkString(transition.attributeValue(
                                        "name"));

                            String fromStepNo = StringTool.checkString(transition.attributeValue(
                                        "from"));

                            String toStepNo = StringTool.checkString(transition.attributeValue(
                                        "to"));

                            String fromStepId = (String) newStepMap.get(fromStepNo);

                            String toStepId = (String) newStepMap.get(toStepNo);

                            String sql =
                                "INSERT INTO WF_TREND (S_ID,TREND_ID,TREND_NAME) VALUES (" +
                                fromStepId + "," + toStepId + ",'" + tranName +
                                "')";

                            if (!this.trimmer.execute(sql)) {
                                throw new WorkflowException(
                                    "synchronize workflow xml from drawing error, failure to insert workflow trend.");
                            }
                        }
                    }
                }

                List steps = flow.isteps();

                for (int i = 0; i < steps.size(); i++) {
                    WStep step = (WStep) steps.get(i);

                    /*删除该节点*/
                    if (!newStepMap.containsKey(String.valueOf(step.ino()))) {
                        deleteStep(step.id());
                    }
                }
            }
        } catch (Exception ex) {
            throw new WorkflowException("synchronize workflow xml from drawing error.",
                ex);
        }
    }

    /**
     * 流程中是否存在指定ID的环节
     * @param flowid 流程ID
     * @param stepno 环节序号
     * @return boolean
     */
    public boolean exitsStep(String flowid, String stepno) {
        String sql = "SELECT * FROM WF_STEP WHERE CG_ID = " + flowid +
            " AND S_NO = " + stepno;

        return this.trimmer.haveMoreData(sql);
    }

    /**
     * 根据流程ID和环节序列号获得环节信息
     * @param flowid 流程ID
     * @param stepno 环节序列号
     * @return Map
     */
    public Map getStepByNo(String flowid, String stepno) {
        String sql = "SELECT * FROM WF_STEP WHERE CG_ID = " + flowid +
            " AND S_NO = " + stepno;

        return this.trimmer.searchSingleData(sql);
    }

    /**
     * 流程中是否存在指定ID的环节
     * @param fromStepId from环节ID
     * @param toStepId to环节ID
     * @return boolean
     */
    public boolean exitsTrend(String fromStepId, String toStepId) {
        String sql = "SELECT * FROM WF_TREND WHERE S_ID = " + fromStepId +
            " AND TREND_ID = " + toStepId;

        return this.trimmer.haveMoreData(sql);
    }

    /**
     * 流程中是否存在指定ID的环节
     * @param fromStepId from环节ID
     * @param toStepId to环节ID
     * @return Map
     */
    public Map getTrend(String fromStepId, String toStepId) {
        String sql = "SELECT * FROM WF_TREND WHERE S_ID = " + fromStepId +
            " AND TREND_ID = " + toStepId;

        return this.trimmer.searchSingleData(sql);
    }

    /**
     * 获得流向参与人列表
     * @param stepId 当前环节
     * @param user 会话用户
     * @return List
     * @throws WorkflowException
     */
    public List getTrendUser(String activityId, String stepId, IUser user)
        throws WorkflowException {
        WStep step = this.getStepByID(stepId);

        List trends = step.itrend();

        List resultList = new ArrayList();

        if ((trends != null) && !trends.isEmpty()) {
            WorkflowEngine engine = new WorkflowEngine(conn);

            for (int i = 0; i < trends.size(); i++) {
                WTrend trend = (WTrend) trends.get(i);
                WStep nextStep = step.iflow().istep(trend.itrendid());

                /*参与人类型为角色*/
                if (!nextStep.itrans() && (step.inner() <= nextStep.inner()) &&
                        (nextStep.irangetype() == 1)) {
                    List list = engine.getStepUsers(nextStep, user);

                    GroupJsonBean stepNode = new GroupJsonBean();

                    stepNode.setId("step_" + nextStep.id());
                    stepNode.setText(nextStep.iname());
                    stepNode.setRealid(nextStep.id());
                    stepNode.setType(String.valueOf(nextStep.itype()));
                    stepNode.setIconCls("step");
                    stepNode.setCls("oaFont");

                    stepNode.setChildren(list);

                    resultList.add(stepNode);
                } else if (!nextStep.itrans() &&
                        (step.inner() > nextStep.inner())) {
                    /*分支节点办理完毕,即将跳转出分支环节时,将进入该分支办理环节前的节点办理人作为默认的文件接收人*/
                    WInstanceManager im = new WInstanceManager(conn);

                    WActivity activity = im.getActivityByID(activityId);

                    WActivity theActivity = activity.instance().inner4before(activity.iprocess());

                    IUser u = theActivity.iexecutor().iuser();

                    List list = new ArrayList();

                    GroupJsonBean userNode = new GroupJsonBean4Chk();
                    userNode.setId("step_" + nextStep.id() + "_u_" + u.id());
                    userNode.setText(u.iname());
                    userNode.setRealid(u.id());
                    userNode.setType("user");
                    userNode.setLeaf(true);
                    userNode.setParentId(nextStep.id());
                    list.add(userNode);

                    GroupJsonBean stepNode = new GroupJsonBean();

                    stepNode.setId("step_" + nextStep.id());
                    stepNode.setText(nextStep.iname());
                    stepNode.setRealid(nextStep.id());
                    stepNode.setType("step");
                    stepNode.setIconCls("step");
                    stepNode.setCls("oaFont");

                    stepNode.setChildren(list);

                    resultList.add(stepNode);
                } else if (nextStep.itrans()) {
                    List tempList = getTrendUser(activityId, nextStep.id(), user);

                    resultList.addAll(tempList);
                }
            }
        }

        return resultList;
    }

    /**
     * 获得流向参与人列表
     * @param activityId 活动记录
     * @param step 当前环节
     * @param nextStep 下一环节
     * @param user 会话用户
     * @return List
     * @throws WorkflowException
     */
    public List getSDTrendUser(String activityId, WStep step, WStep nextStep,
        IUser user) throws WorkflowException {
        List resultList = new ArrayList();

        WorkflowEngine engine = new WorkflowEngine(conn);

        /*参与人类型为角色*/
        if (!nextStep.itrans() && (step.inner() <= nextStep.inner()) &&
                (nextStep.irangetype() == 1)) {
            List list = engine.getStepUsers(nextStep, user);

            GroupJsonBean stepNode = new GroupJsonBean();

            stepNode.setId("step_" + nextStep.id());
            stepNode.setText(nextStep.iname());
            stepNode.setRealid(nextStep.id());
            stepNode.setType("step");
            stepNode.setIconCls("step");
            stepNode.setCls("oaFont");

            stepNode.setChildren(list);

            resultList.add(stepNode);
        } else if (!nextStep.itrans() && (step.inner() > nextStep.inner())) {
            /*分支节点办理完毕,即将跳转出分支环节时,将进入该分支办理环节前的节点办理人作为默认的文件接收人*/
            WInstanceManager im = new WInstanceManager(conn);

            WActivity activity = im.getActivityByID(activityId);

            WActivity theActivity = activity.instance().inner4before(activity.iprocess());

            IUser u = theActivity.iexecutor().iuser();

            List list = new ArrayList();

            GroupJsonBean userNode = new GroupJsonBean4Chk();
            userNode.setId("step_" + nextStep.id() + "_u_" + u.id());
            userNode.setText(u.iname());
            userNode.setRealid(u.id());
            userNode.setType("user");
            userNode.setLeaf(true);
            userNode.setParentId(nextStep.id());
            list.add(userNode);

            GroupJsonBean stepNode = new GroupJsonBean();

            stepNode.setId("step_" + nextStep.id());
            stepNode.setText(nextStep.iname());
            stepNode.setRealid(nextStep.id());
            stepNode.setType("step");
            stepNode.setIconCls("step");
            stepNode.setCls("oaFont");

            stepNode.setChildren(list);

            resultList.add(stepNode);
        } else if (nextStep.itrans()) {
            List tempList = getTrendUser(activityId, nextStep.id(), user);

            resultList.addAll(tempList);
        }

        return resultList;
    }

    /**
     * 删除流程环节
     * @param id
     */
    public void deleteStep(String id) throws WorkflowException {
        String sql1 = "SELECT A_ID FROM WF_ACTIVITY WHERE S_ID = ?";

        DataItemList dil = this.trimmerI.createDIL();
        dil.set(id);

        if (!this.trimmerI.haveMoreData(sql1, dil)) {
            StringBuffer sql = new StringBuffer();

            sql.append("DELETE FROM WF_STEP WHERE S_ID =" + id);
            sql.append(";");
            sql.append("DELETE FROM WF_TREND WHERE S_ID = " + id);
            sql.append(";");
            sql.append("DELETE FROM WF_TREND WHERE TREND_ID = " + id);
            sql.append(";");
            sql.append("DELETE FROM WF_HANDLE WHERE S_ID = " + id);

            if (!this.trimmer.executeBatch(sql.toString())) {
                throw new WorkflowException("delete workflow step['" + id +
                    "'] error.");
            }
        } else {
            throw new WorkflowException("workflow step['" + id + "'] in used.");
        }
    }

    /**
     * 使流程环节无效
     * @param id 环节ID
     */
    public void invalidateStep(String id) throws WorkflowException {
        StringBuffer sql = new StringBuffer();

        sql.append("UPDATE WF_STEP SET S_STATUS = -1 WHERE S_ID =" + id);

        if (!this.trimmer.executeBatch(sql.toString())) {
            throw new WorkflowException("invalidate workflow step['" + id +
                "'] error.");
        }
    }

    /**
     * 使流程环节有效
     * @param id 环节ID
     */
    public void validateStep(String id) throws WorkflowException {
        StringBuffer sql = new StringBuffer();

        sql.append("UPDATE WF_STEP SET S_STATUS = 0 WHERE S_ID =" + id);

        if (!this.trimmer.executeBatch(sql.toString())) {
            throw new WorkflowException("validate workflow step['" + id +
                "'] error.");
        }
    }

    /**
     * 上一流程环节ID
     * @param id
     * @return String
     */
    private String[] getStepLastID(String id) {
        String[] lastid = null;
        String sql = "SELECT S_ID FROM WF_TREND WHERE TREND_ID = " + id;

        List list = this.trimmer.searchMultiData(sql);

        if ((list != null) && !list.isEmpty()) {
            lastid = new String[list.size()];

            for (int i = 0; i < list.size(); i++) {
                Map temp = (Map) list.get(i);
                lastid[i] = (String) temp.get("S_ID");
            }
        }

        return lastid;
    }

    /**
     * 流程环节NO
     * @param id 环节ID
     * @return String
     */
    private String getStepNO(String id) {
        String no = "0";

        String sql = "SELECT S_NO FROM WF_STEP WHERE S_ID = " + id;

        Map info = this.trimmer.searchSingleData(sql);

        if (info != null) {
            no = (String) info.get("S_NO");
        }

        return no;
    }

    /**
     * 流程环节流向
     * @param sid
     * @return List
     */
    private List getStepTrend(String sid) {
        String sql = "SELECT * FROM WF_TREND WHERE S_ID = " + sid +
            " ORDER BY TREND_SORT ASC";

        List list = this.trimmer.searchMultiData(sql);

        for (int i = 0; i < list.size(); i++) {
            Map temp = (Map) list.get(i);

            String tid = (String) temp.get("TREND_ID");

            String sno = this.getStepNO(sid);
            String tno = this.getStepNO(tid);

            temp.put("S_NO", sno);
            temp.put("T_NO", tno);

            WTrend trend = new WTrendImpl();
            trend.reload(temp);

            list.set(i, trend);
        }

        return list;
    }

    /**
     * 环节操作权限
     * @param sid
     * @return
     */
    private List getStepHandle(String sid) {
        String sql = "SELECT * FROM WF_HANDLE WHERE S_ID = " + sid;

        List list = this.trimmer.searchMultiData(sql);

        if ((list != null) && !list.isEmpty()) {
            TableRegisterCenter center = TableRegisterCenter.getInstance();

            for (int i = 0; i < list.size(); i++) {
                Map temp = (Map) list.get(i);

                WHandle handle = new WHandleImpl();

                String tname = (String) temp.get("OBJ_TABLE");

                Table table = center.findTable(tname);

                temp.put("OBJ_TABLE", table);

                handle.reload(temp);

                list.set(i, handle);
            }
        }

        return list;
    }

    /**
     * 获得指定类型的文号
     * @param type 文号类型
     * @param objkey 对象类型
     * @return List
     */
    public List getNumberType(String type, String objkey) {
        String sql = "SELECT * FROM WF_NUMBER_TYPE WHERE OBJ_TYPE = ? AND WOBJECT = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(type);
        dil.set(objkey);

        return this.trimmerI.searchMultiData(sql, dil);
    }

    /**
     * 得到用户默认文号
     * @param numbers
     * @param user
     * @param objkey
     * @return Map
     */
    public Map getDefaultNumber4User(IUser user, String objkey) {
        String[] strs = user.igroupflumeid(",").split(",");
        Map info = null;
        int c = strs.length;

        while (c > 0) {
            String str = strs[c - 1];
            String sql = "SELECT * FROM WF_NUMBER_TYPE WHERE OBJ_TYPE = ? AND OBJ_ID = ? AND WOBJECT = ?";

            DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

            dil.set("GROUP");

            dil.set(str);

            dil.set(objkey);

            Map temp = this.trimmerI.searchSingleData(sql, dil);

            if (temp != null) {
                info = temp;

                break;
            }

            c--;
        }

        return info;
    }

    /**
     * 获取公文模板
     *
     * @param gid 流程类别ID
     * @return List
     */
    public List getDocTemp(String gid) {
        String sql = "SELECT * FROM WF_DOCTEMP WHERE CG_ID = '" + gid +
            "' ORDER BY TEMP_NAME";

        List resultList = this.trimmer.searchMultiData(sql);

        if (!resultList.isEmpty()) {
            AnnexTool tool = new AnnexTool(conn);

            for (int i = 0; i < resultList.size(); i++) {
                Map info = (Map) resultList.get(i);

                String docid = (String) info.get("TEMP_ID");

                AnnexInfo[] annexs = tool.getAnnexs(docid, "WF_DOCTEMP");

                if ((annexs != null) && (annexs.length > 0)) {
                    info.put("ANNEXID", annexs[0].getID());
                }
            }
        }

        return resultList;
    }

    /**
     * 获取公文模板(默认使用中的)
     *
     * @param gid 流程类别ID
     * @return Map
     */
    public Map getDocTempInUsed(String gid) {
        String sql = "SELECT * FROM WF_DOCTEMP WHERE CG_ID = ? AND TEMP_USED = 1 ORDER BY TEMP_NAME";

        DataItemList dil = this.trimmerI.createDIL();

        dil.set(gid);

        Map map = this.trimmerI.searchSymmetricalMap(sql, "TEMP_TYPE", dil);

        if (!map.isEmpty()) {
            AnnexTool tool = new AnnexTool(conn);

            Iterator keys = map.keySet().iterator();

            while (keys.hasNext()) {
                String key = (String) keys.next();

                Map info = (Map) map.get(key);

                String docid = (String) info.get("TEMP_ID");

                AnnexInfo[] annexs = tool.getAnnexs(docid, "WF_DOCTEMP");

                if ((annexs != null) && (annexs.length > 0)) {
                    info.put("ANNEXID", annexs[0].getID());
                }
            }
        }

        return map;
    }

    /**
     * 获取公文模板
     * @param type 模板类型(0正文,1套红,2版记,3打印)
     * @param gid 流程类别ID
     * @return List
     */
    public List getDocTemp(int type, String gid) {
        String sql = "SELECT * FROM WF_DOCTEMP WHERE TEMP_TYPE = ? AND CG_ID = ? ORDER BY TEMP_USED ASC, TEMP_NAME ASC";

        DataItemList dil = this.trimmerI.createDIL();

        dil.set(type);
        dil.set(gid);

        List list = this.trimmerI.searchMultiData(sql, dil);

        if ((list != null) && !list.isEmpty()) {
            AnnexTool tool = new AnnexTool(conn);

            for (int i = 0; i < list.size(); i++) {
                Map info = (Map) list.get(i);

                String docid = (String) info.get("TEMP_ID");

                AnnexInfo[] annexs = tool.getAnnexs(docid, "WF_DOCTEMP");

                if ((annexs != null) && (annexs.length > 0)) {
                    info.put("ANNEXID", annexs[0].getID());
                }
            }
        }

        return list;
    }

    /**
     * 得到待办列表URL
     * @param key 流转对象key
     * @return String
     */
    public static String getPendingURL(String key) {
        /*默认(全部对象)列表*/
        String url = "/flowlist.do?method=mypendinglist";

        if (!key.equals("")) {
            WObject obj = null;
            WObjectRegister register = WObjectRegister.getInstance();

            try {
                obj = register.findWObject(key);
            } catch (Exception ex) {
                ISystem.catchException(ex);
            }

            /*自定义列表*/
            if (!obj.iview4pending().equals("")) {
                url = "/flowlist.do?method=pendinglist&key=" + key;
            }
            /*默认(对象)列表*/
            else {
                url += ("&key=" + key);
            }
        }

        return url;
    }

    /**
     * 得到待办列表URL
     * @param key 流转对象key
     * @return String
     */
    public static String getDoneURL(String key) {
        /*默认(全部对象)列表*/
        String url = "/flowlist.do?method=mydonelist";

        if (!key.equals("")) {
            WObject obj = null;
            WObjectRegister register = WObjectRegister.getInstance();

            try {
                obj = register.findWObject(key);
            } catch (Exception ex) {
                ISystem.catchException(ex);
            }

            /*自定义列表*/
            if (!obj.iview4done().equals("")) {
                url = "/flowlist.do?method=donelist&key=" + key;
            }
            /*默认(对象)列表*/
            else {
                url += ("&key=" + key);
            }
        }

        return url;
    }

    /**
     * 得到传阅列表URL
     * @param key 流转对象key
     * @return String
     */
    public static String getEncyclicURL(String key) {
        /*默认(全部对象)列表*/
        String url = "/flowlist.do?method=myencycliclist";

        if (!key.equals("")) {
            WObject obj = null;
            WObjectRegister register = WObjectRegister.getInstance();

            try {
                obj = register.findWObject(key);
            } catch (Exception ex) {
                ISystem.catchException(ex);
            }

            /*自定义列表*/
            if (!obj.iview4encyclic().equals("")) {
                url = "/flowlist.do?method=encycliclist&key=" + key;
            }
            /*默认(对象)列表*/
            else {
                url += ("&key=" + key);
            }
        }

        return url;
    }

    /**
     * 得到抄送列表URL
     * @param key 流转对象key
     * @return String
     */
    public static String getCCURL(String key) {
        /*默认(全部对象)列表*/
        String url = "/flowlist.do?method=mycclist";

        if (!key.equals("")) {
            WObject obj = null;
            WObjectRegister register = WObjectRegister.getInstance();

            try {
                obj = register.findWObject(key);
            } catch (Exception ex) {
                ISystem.catchException(ex);
            }

            /*自定义列表*/
            if (!obj.iview4cc().equals("")) {
                url = "/flowlist.do?method=cclist&key=" + key;
            }
            /*默认(对象)列表*/
            else {
                url += ("&key=" + key);
            }
        }

        return url;
    }

    /**
     * 临时流程环节信息
     *
     * @return WStep
     */
    public static WStep getTempStep() {
        Map info = new HashMap();
        info.put("S_ID", "");
        info.put("S_NAME", "");
        info.put("S_NO", "0");
        info.put("S_TYPE", "0");
        info.put("S_CORR", "-1");
        info.put("S_CORRS", "-1");
        info.put("S_INNER", "-1");
        info.put("S_PARA", "-1");
        info.put("S_CORRVALUE", "-1");
        info.put("S_CORRSVALUE", "-1");

        WStep step = new WStepImpl();
        step.reload(info);

        return step;
    }

    /**
     * 临时流程环节信息
     *
     * @return WStep
     */
    public static WStep getTempStep(WFlow flow, int inner) {
        Map info = new HashMap();
        info.put("S_ID", "0");
        info.put("S_NAME", "");
        info.put("S_NO", "0");
        info.put("S_TYPE", "1");
        info.put("S_CORR", "-1");
        info.put("S_CORRS", "-1");
        info.put("S_INNER", String.valueOf(inner));
        info.put("S_PARA", "-1");
        info.put("S_CORRVALUE", "-1");
        info.put("S_CORRSVALUE", "-1");
        ;

        WStep step = new WStepImpl(flow);
        step.reload(info);

        return step;
    }

    /**
     * 流程拷贝
     * @param name 流程名称
     * @param key 唯一标识
     * @param object 流转对象key
     * @param id 待复制流程ID
     */
    public void copy(String name, String key, String object, String id)
        throws WorkflowException {
        WFlow flow = this.getWFlowById(id);

        if (flow == null) {
            throw new WorkflowException("workflow[" + id + "] is not exits.");
        }

        SimpleBean4Table sbt = new SimpleBean4TableImpl("WF_CATEGORY");

        sbt.getResource().put("ikey", key);
        sbt.getResource().put("iname", name);
        sbt.getResource().put("iobj", object);

        String fid = null;

        BaseworkUtil util = new BaseworkUtil();

        try {
            Map info = (Map) util.manualSave1(sbt, this.conn);
            fid = (String) info.get("CG_ID");
        } catch (Exception ex) {
            throw new WorkflowException("copy workflow[" + id + "] error.", ex);
        }

        List steps = flow.isteps();

        if ((steps != null) && !steps.isEmpty()) {
            Map oldnewMap = new HashMap();

            for (int i = 0; i < steps.size(); i++) {
                WStep step = (WStep) steps.get(i);

                SimpleBean4Table stepSBT = new SimpleBean4TableImpl("WF_STEP");
                stepSBT.getResource().put("iname", step.iname());
                stepSBT.getResource().put("imemo", step.imemo());
                stepSBT.getResource().put("gid", fid);
                stepSBT.getResource().put("ino", step.ino());
                stepSBT.getResource().put("xc", step.ixCoordinate());
                stepSBT.getResource().put("yc", step.iyCoordinate());
                stepSBT.getResource().put("itype", step.itype());
                stepSBT.getResource().put("irangetype", step.irangetype());
                stepSBT.getResource().put("isroleid", step.irangeids());
                stepSBT.getResource().put("isrolename", step.irangenames());
                stepSBT.getResource().put("iscorr", step.iscorr());
                stepSBT.getResource().put("ipara", step.ipara());
                stepSBT.getResource().put("iparavalue", step.iparavalue());
                stepSBT.getResource().put("iinner", step.inner());
                stepSBT.getResource().put("itrans", step.itrans() ? "1" : "0");
                stepSBT.getResource().put("isenders", step.isenders());
                stepSBT.getResource().put("icc", step.icc());
                stepSBT.getResource().put("ired",
                    step.getResource().get("S_RED"));
                stepSBT.getResource().put("iplugxml", step.iplugXML());
                stepSBT.getResource().put("istatus", step.istatus());

                String sid = null;

                try {
                    Map info = (Map) util.manualSave1(stepSBT, this.conn);
                    sid = (String) info.get("S_ID");
                } catch (Exception ex) {
                    throw new WorkflowException("copy workflow[" + id +
                        "] step error.", ex);
                }

                oldnewMap.put(step.id(), sid);
            }

            for (int i = 0; i < steps.size(); i++) {
                WStep step = (WStep) steps.get(i);

                List trends = step.itrend();

                if ((trends != null) && !trends.isEmpty()) {
                    for (int j = 0; j < trends.size(); j++) {
                        WTrend trend = (WTrend) trends.get(j);

                        SimpleBean4Table trendSBT = new SimpleBean4TableImpl(
                                "WF_TREND");
                        trendSBT.getResource().put("sid",
                            oldnewMap.get(trend.istepid()));
                        trendSBT.getResource().put("tid",
                            oldnewMap.get(trend.itrendid()));
                        trendSBT.getResource().put("tname", trend.itrendname());
                        trendSBT.getResource().put("tsort", trend.itrendno());
                        trendSBT.getResource().put("tselect",
                            trend.iselect() ? "1" : "0");

                        try {
                            util.manualSave1(trendSBT, this.conn);
                        } catch (Exception ex) {
                            throw new WorkflowException("copy workflow[" + id +
                                "] trend error.", ex);
                        }
                    }
                }
            }
        }
    }
}
